package org.poem.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.poem.CanalApplicationContext;
import org.poem.CommonVO;
import org.poem.IdsVo;
import org.poem.datasource.DataAndParametersVo;
import org.poem.datasource.DataSourceQueryVo;
import org.poem.datasource.DataSourceVo;
import org.poem.datasource.table.SchemaVO;
import org.poem.datasource.table.TableVO;
import org.poem.entity.TDatasource;
import org.poem.exception.CanalClientException;
import org.poem.mapper.TDataSourceMapper;
import org.poem.result.PageableResult;
import org.poem.service.ITDataSourceService;
import org.poem.tool.GatherBuilder;
import org.poem.tool.GatherConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 数据源 服务实现类
 * </p>
 *
 * @author vinshine
 * @since 2019-10-24
 */
@Service
public class TDataSourceServiceImpl extends ServiceImpl<TDataSourceMapper, TDatasource> implements ITDataSourceService {

    private static final Logger logger = LoggerFactory.getLogger(TDataSourceServiceImpl.class);


    @Autowired
    private MysqlGatherData mysqlGatherData;

    /**
     * 01-加载数据源首页+分页
     *
     * @param dataSourceQueryVo 查询条件
     * @param pageSize          每页大小
     * @param pageNumber        当前页码
     * @return
     */
    @Override
    public PageableResult<DataSourceVo> findDataSourceList(DataSourceQueryVo dataSourceQueryVo, Integer pageSize, Integer pageNumber) {
        //查询条件对象
        QueryWrapper<TDatasource> ew = new QueryWrapper<>();
        //使用条件查询
        if (StringUtils.isNotEmpty(dataSourceQueryVo.getSourceName())) {
            ew.lambda().like(TDatasource::getName, dataSourceQueryVo.getSourceName());
        }

        //分页插件
        IPage<TDatasource> tDataSourceIPage = this.page(new Page<>(pageNumber, pageSize), ew);
        PageableResult<DataSourceVo> pageableResult = new PageableResult<>();
        pageableResult.setCurrent(tDataSourceIPage.getCurrent());
        pageableResult.setSize(tDataSourceIPage.getSize());
        pageableResult.setTotal(tDataSourceIPage.getTotal());
        //将查询出来的值set到VO对象中
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        pageableResult.setVoList(tDataSourceIPage.getRecords().stream().map(
                o -> {
                    DataSourceVo dataSourceVo = new DataSourceVo();
                    dataSourceVo.setContent(o.getContent());
                    dataSourceVo.setDataDirection(o.getDataDirection());
                    dataSourceVo.setDrive(o.getDrive());
                    LocalDateTime createTime = o.getCreateTime();
                    String time = df.format(createTime);
                    dataSourceVo.setCreateTime(time);
                    dataSourceVo.setId(o.getId());
                    dataSourceVo.setSourceType(o.getSourceType());
                    dataSourceVo.setPassword(o.getPassword());
                    dataSourceVo.setSourceName(o.getName());
                    dataSourceVo.setIp(o.getIp());
                    dataSourceVo.setPort(o.getPort());

                    dataSourceVo.setUserName(o.getUserName());
                    return dataSourceVo;
                }
        ).collect(Collectors.toList()));
        return pageableResult;
    }

    /**
     * 02-新建数据源
     *
     * @param dataSourceVo
     * @return
     */
    @Override
    public String addDataSource(DataSourceVo dataSourceVo, Long dataSourceId) {

        TDatasource tDataSource = new TDatasource();
        tDataSource.setContent(dataSourceVo.getContent());
        tDataSource.setCreateTime(LocalDateTime.now());

        //获取当前用户
        tDataSource.setId(dataSourceId);
        tDataSource.setDataDirection(dataSourceVo.getDataDirection());
        tDataSource.setDrive(dataSourceVo.getDrive());
        tDataSource.setStatus(1);
        tDataSource.setSourceSchema(dataSourceVo.getSourceSchema());
        tDataSource.setPassword(dataSourceVo.getPassword());
        tDataSource.setName(dataSourceVo.getSourceName());
        tDataSource.setUpdateTime(LocalDateTime.now());
        //获取当前用户
        tDataSource.setSourceType(dataSourceVo.getSourceType());
        tDataSource.setSourceType(dataSourceVo.getSourceType());
        tDataSource.setIp(dataSourceVo.getIp());
        tDataSource.setPort(dataSourceVo.getPort());

        tDataSource.setUserName(dataSourceVo.getUserName());
        boolean b = this.save(tDataSource);
        if (b) {
            return "新增数据源成功！";
        } else {
            return "新增数据源失败！";
        }
    }

    /**
     * 03-根据数据源id查询数据源详情
     *
     * @param dataSourceId 数据源id
     * @return
     */
    @Override
    public DataSourceVo getDataSourceVoById(Long dataSourceId) {

        TDatasource o = this.getById(dataSourceId);
        DataSourceVo dataSourceVo = new DataSourceVo();
        dataSourceVo.setContent(o.getContent());
        dataSourceVo.setDataDirection(o.getDataDirection());
        dataSourceVo.setDrive(o.getDrive());
        dataSourceVo.setId(o.getId());
        dataSourceVo.setSourceType(o.getSourceType());
        dataSourceVo.setPassword(o.getPassword());
        dataSourceVo.setSourceName(o.getName());
        dataSourceVo.setIp(o.getIp());
        dataSourceVo.setPort(o.getPort());
        dataSourceVo.setSourceSchema(o.getSourceSchema());
        dataSourceVo.setUserName(o.getUserName());
        return dataSourceVo;
    }

    /**
     * 04-修改数据源
     *
     * @param dataSourceVo
     * @return
     */
    @Override
    public String updateDataSource(DataSourceVo dataSourceVo) {
        if (dataSourceVo == null) {
            return "数据为空";
        }
        TDatasource tDataSource = this.getById(dataSourceVo.getId());
        tDataSource.setId(dataSourceVo.getId());
        tDataSource.setContent(dataSourceVo.getContent());
        tDataSource.setDataDirection(dataSourceVo.getDataDirection());
        tDataSource.setDrive(dataSourceVo.getDrive());
        tDataSource.setPassword(dataSourceVo.getPassword());
        tDataSource.setName(dataSourceVo.getSourceName());
        tDataSource.setUpdateTime(LocalDateTime.now());
        tDataSource.setSourceSchema(dataSourceVo.getSourceSchema());

        //获取当前用户
        tDataSource.setIp(dataSourceVo.getIp());
        tDataSource.setPort(dataSourceVo.getPort());

        tDataSource.setUserName(dataSourceVo.getUserName());
        boolean b = this.saveOrUpdate(tDataSource);
        if (b) {
            return "数据源修改成功！";
        } else {
            return "数据源修改失败！";
        }
    }


    /**
     * 05-根据数据源id删除数据源
     *
     * @param dataSourceId 数据源id
     * @return
     */
    @Override
    public String deleteDataSourceById(Long dataSourceId) {
        QueryWrapper<TDatasource> ew = new QueryWrapper<>();
        //根据条件删除
        ew.lambda().eq(TDatasource::getId, dataSourceId);
        boolean b = this.remove(ew);
        if (b) {
            return "数据源删除成功！";
        } else {
            return "数据源删除失败！";
        }
    }

    /**
     * 06-根据数据源id批量删除
     *
     * @param idsVo 数据源id数组
     * @return
     */
    @Override
    public String deleteDataSource(IdsVo idsVo) {
        Long[] ids = idsVo.getIds();
        List<Long> strings = Arrays.asList(ids);
        //根据条件删除
        boolean b = this.removeByIds(strings);
        if (b) {
            return "批量删除成功！";
        }
        return "批量删除失败！";
    }

    /**
     * @param subjectId
     * @return
     */
    @Override
    public List<CommonVO> getDatasourceList(Long subjectId) {
        //查询条件对象
        QueryWrapper<TDatasource> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(true, TDatasource::getDataDirection, "IN_OUT").or().eq(true, TDatasource::getDataDirection, "OUT");
        List<TDatasource> dataSources = list(queryWrapper);
        return dataSources.parallelStream().map(
                o -> {
                    CommonVO commonVO = new CommonVO();
                    if (StringUtils.isNotEmpty(o.getSourceSchema())) {
                        commonVO.setName(o.getName() + "(" + o.getSourceSchema() + ")");
                    } else {
                        commonVO.setName(o.getName());
                    }
                    commonVO.setId(Long.toString(o.getId()));
                    return commonVO;
                }
        ).collect(Collectors.toList());
    }

    /**
     * 测试连接
     *
     * @param dataSourceVo
     * @throws CanalClientException
     */
    @Override
    public void testDataSource(DataAndParametersVo dataSourceVo) throws CanalClientException {
        if ("mysql".equalsIgnoreCase(dataSourceVo.getDataSourceVo().getSourceType())) {
            AbstractDatasource datasource = (AbstractDatasource) CanalApplicationContext.getBean(MysqlDatasource.class);
            datasource.testSource(dataSourceVo.getDataSourceVo());
        } else if ("sqlserver".equalsIgnoreCase(dataSourceVo.getDataSourceVo().getSourceType())) {
            AbstractDatasource datasource = (PostgresDatasource) CanalApplicationContext.getBean(PostgresDatasource.class);
            datasource.testSource(dataSourceVo.getDataSourceVo());
        }

    }

    /***
     * 获取数据库信息
     * @param dataSourceVo
     * @return
     */
    @Override
    public List<String> getSchema(DataAndParametersVo dataSourceVo) {
        logger.info(" init getSchema :" + JSONObject.toJSONString(dataSourceVo));
        DataSourceVo da = dataSourceVo.getDataSourceVo();
        GatherConnection connection = new GatherBuilder()
                .sourceType(dataSourceVo.getDataSourceVo().getSourceType())
                .ip(da.getIp())
                .password(da.getPassword())
                .port(da.getPort())
                .user(da.getUserName())
                .builder();
        return mysqlGatherData.getSchema(connection.getConnection(), dataSourceVo.getDataSourceVo().getSourceType());
    }

    /**
     *
     * @param datasourceId
     * @return
     */
    @Override
    public List<TableVO> getDatabaseBySourceId(String datasourceId) {
        TDatasource dataSource = this.getById(datasourceId);
        if (dataSource == null) {
            throw new IllegalArgumentException("this entity[" + datasourceId + "] is not exist.");
        }
        logger.info(" init connection :" + JSONObject.toJSONString(dataSource));
        GatherConnection connection = new GatherBuilder()
                .sourceSchema(dataSource.getSourceSchema())
                .sourceType(dataSource.getSourceType())
                .ip(dataSource.getIp())
                .password(dataSource.getPassword())
                .port(dataSource.getPort())
                .user(dataSource.getUserName())
                .builder();
        return  mysqlGatherData.getDataBases(connection.getConnection(),dataSource.getSourceType(),dataSource.getSourceSchema());
    }
}
